#include <stdio.h>
#include <stdlib.h>

#include "DLList.h"

#define true 1
#define false 0 
int  InitDLList(DLList *list)
{
    list->len = 0 ;
    list->head = NULL;
    list->tail = NULL;

    return true;
}

void FreeDLinkLIst(DLList *list,void(*func)(ElementType))
{
    if(list->len == 0)
    {return ;}
    list->tail->next = NULL ; 


    while(list->head != NULL)
    {
        struct Node* nextNode = list->head->next;
        func(nextNode->data);
        free(list->head);
        list->head = nextNode ;
    }
    list->len = 0 ;
    list->head = NULL;
    list->tail = NULL;

}
struct Node* CreateNode(ElementType element)
{
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));

    if(newNode == NULL)
    {
        printf("createNode malloc error!\n");
        return NULL ;
    }
    newNode->data = element;
    newNode->next = NULL;
    newNode->prev = NULL;

    return newNode;
}


void TravelDLL(DLList *list,void(*func)(ElementType))
{
    struct Node* TravelPoint = list->head;
    while(TravelPoint != NULL)
    {
        if(func != NULL)
        {
            func(TravelPoint->data);
        }
       // printf("%d ",TravelPoint->data);
        TravelPoint = TravelPoint->next;
    }
    printf("\n");


//     TravelPoint = list->tail;
//     printf("prev : ");
//     while(TravelPoint != NULL)
//     {
//         printf("%d ",TravelPoint->data);
//         TravelPoint = TravelPoint->prev;
//     }
//     printf("\n");



}

void InsertTail(DLList *list,ElementType element)
{
    struct Node* newNode = CreateNode(element);
    if(newNode == NULL)
    {
        printf("insertTail malloc error!\n");
        return ;
    }

    if(list->len == 0)
    {
        list->head = newNode ;
        list->tail = newNode ;
    }
    else
    {
        list->tail->next = newNode;
        newNode->prev = list->tail ;
        list->tail = newNode ;
    }
        list->len ++;


}

void InsertHead(DLList *list, ElementType element)
{
    struct Node* newNode = CreateNode(element);
    if(newNode == NULL)
    {
        printf("insertHead malloc error!\n");
        return ;
    }
    if(list->len == 0)
    {
        list->head = newNode ;
        list->tail = newNode ;
    }
    else
    {
        list->head->prev = newNode;
        newNode->next = list->head ;
        list->head = newNode ;
    }
        list->len ++;

}

void InsertIndex(DLList *list, ElementType element, int index)
{
    if(index < 0 || index > list->len)
    {
        printf("insertIndex invalid place!\n");
        return ;
    }
    
    struct Node* newNode = CreateNode(element);
    struct Node* TravelPoint = list->head ;

    if(index == 0)
    {
        InsertHead(list,element);
        return;
    }

    if(index == list->len-1)
    {
        InsertTail(list,element);
        return ;
    }

    int count = 0 ;
    while(count < index - 1)
    {
        TravelPoint = TravelPoint->next ;
        count++ ;
    }

    newNode->next = TravelPoint ->next ;
    TravelPoint->next->prev = newNode ;
    TravelPoint->next = newNode ;
    newNode->prev = TravelPoint ;
    list->len++ ;
}

void RemoveByIndex(DLList *list, int index)
{
    if(index < 0 || index >= list->len)
    {
        printf("RemoveByIndex invalid place!\n");
        return ;
    }

    if(index == 0)
    {
        if(list->len == 1)
        {
            free(list->head) ;
            list->len = 0 ;
            list->head = NULL ;
            list->tail = NULL ;
            return ;
        }
        struct Node* FreeNode = list->head ;
        list->head = list->head->next;
        list->head->prev = NULL ;
        free(FreeNode);
        list->len-- ;
        return ;
    }
    if(index == list->len-1)
    {
        struct Node* FreeNode = list->tail ;
        list->tail = list->tail->prev;
        list->tail->next = NULL ;
        free(FreeNode);
        list->len-- ;
        return ;
    }

    struct Node* TravelPoint = list->head ;
    while(index != 0 )
    {
        TravelPoint = TravelPoint->next ;
        index -- ;
    }

    TravelPoint->prev->next = TravelPoint->next ;
    TravelPoint->next->prev = TravelPoint->prev ;
    free(TravelPoint);
    list->len--;
    return ;
}

void RemoveByElement(DLList *list, ElementType element)
{
   int count = FindFirstByElement(list,element);
    while(count != -1)
    {
        RemoveByIndex(list,count);
        count = FindFirstByElement(list,element);
    }
}

int  FindFirstByElement(DLList *list, ElementType element)
{
    int count = -1 ;
    struct Node* TravelPoint = list->head;
    
    while(TravelPoint != NULL)
    {
        if(TravelPoint->data == element)
        {
            return count + 1 ;
        }
        count++;
        TravelPoint = TravelPoint -> next;
    }

    return -1;
}

int *FindByElement(DLList *list, ElementType element)
{
    int* findVictor = (int*)malloc(sizeof(int)*list->len+1);

    struct Node* TravelPoint = list->head ;
    
    int count = 0 ;
    for(int i = 0 ; i < list->len-1;i++)
    {
        if(TravelPoint->data == element)
        {
            findVictor[count] = i;
            count++;
        }
        TravelPoint = TravelPoint->next;
        
    }

    findVictor[count] = -1 ;

    return findVictor;
}

// int FindByIndex(DLList *list, int index)
// {
//     if(index < 0 || index >= list->len)
//     {
//         printf("find a invalid place!\n");
//         return -1 ;
//     }

//     struct Node* TravelPoint = list->head ;
//     while(index != 0 )
//     {
//         TravelPoint = TravelPoint->next;
//         index--;
//     }


//     return TravelPoint->data;
// }

void SetValueByIndex(DLList *list, int index,ElementType element)
{
     if(index < 0 || index >= list->len)
    {
        printf("set value a invalid place!\n");
        return  ;
    }

     struct Node* TravelPoint = list->head ;
    while(index != 0)
    {
        TravelPoint = TravelPoint->next ;
        index-- ;
    }
    TravelPoint->data = element ;
}

void SetValueByElement(DLList *list, ElementType oldValue, ElementType newValue)
{
    struct Node* TravelPoint = list->head ;
    if(TravelPoint == NULL)
    {
        printf("SetValueByElement error!\n");
        return ;
    }

    while(TravelPoint !=  NULL)
    {
        if(TravelPoint->data == oldValue)
        {
            TravelPoint->data = newValue ;
        }
        TravelPoint = TravelPoint->next ;
    }
}

int GetLListLen(DLList *list)
{
    return list->len;
}
